#include "CloudiskServer.h"
#include "CryptoUtil.h"
#include "workflow/MySQLResult.h"
#include "nlohmann/json.hpp"
#include "wfrest/PathUtil.h"
#include "HashUtil.h"
#include "ParseUtil.h"
#include <map>
#include <string>
#include <sstream>
#include <fstream>
using namespace wfrest;
using namespace protocol;
using std::cout;
using std::endl;
using std::map;
using std::string;
using std::istringstream;
using std::ifstream;
using std::ostringstream;

//用户上传文件到服务器
void CloudiskServer::register_file_upload_modules(){
    m_server.POST("/file/upload",[](const HttpReq *req,HttpResp *resp){
        if(req->content_type()!=MULTIPART_FORM_DATA){
            resp->set_status(HttpStatusBadRequest);
            return;
        }
        
        //验证token
        string url;
        req->get_request_uri(url);
        map<string,string> params = ParseUtil::get_query_param(url);
        string token = params["token"];
        ParseUtil::verify_token(req, resp, [req,resp,token](User user){
            //验证成功则接收form-data
            if(user.id != 0 && CryptoUtil::verify_token(token,user)){
                const Form& form = req->form();
                for(const auto &[_,fileinfo]:form){
                    const auto& [filename,content]=fileinfo;
                    string saveDir = "resources/";
                    string savePath = saveDir + PathUtil::base(filename);
                    cout << "savePath: " << savePath << endl;
                    resp->Save(savePath,std::move(content));

                    //将文件信息保存在tbl_file表中
                    //如果表中已经存在uid相同且hashcode相同的文件，不添加到mysql中直接返回成功信息
                    string hashcode = HashUtil::compute(content);
                    string size = std::to_string(content.size());
                    string sql_select = "select * from tbl_file where uid="+
                    std::to_string(user.id) + " and hashcode='" + hashcode + "';";
                    resp->MySQL(mysql_url,sql_select,[resp,user,filename,hashcode,size](MySQLResultCursor *cursor){
                        if(cursor->get_rows_count()>0){
                            //跳转回首页
                            resp->set_status(HttpStatusFound);
                            resp->set_header_pair("Location","/static/view/home.html");
                        }else{
                            string sql_insert = "insert into tbl_file (uid,filename,hashcode,size) values ('"
                            + std::to_string(user.id) + "','" + filename + "','" + hashcode + "','" 
                            + size + "');";
                            cout << "[SQL]" << sql_insert << endl;
                            resp->MySQL(mysql_url,sql_insert,[resp](MySQLResultCursor *cursor){
                                if(cursor->get_cursor_status()==MYSQL_STATUS_OK){
                                     //跳转回首页
                                    resp->set_status(HttpStatusFound);
                                    resp->set_header_pair("Location","/static/view/home.html");
                                }else{
                                    resp->set_status(HttpStatusInternalServerError);
                                }
                            });
                        }
                    });
                }
            }else{
                //验证失败
                resp->set_status(HttpStatusUnauthorized);
            }
        });
        
    });
}

//用户从服务器下载文件
void CloudiskServer::register_file_download_modules(){
    m_server.GET("/file/download",[](const HttpReq *req,HttpResp *resp){
        //验证token
        string url;
        req->get_request_uri(url);
        map<string,string> params = ParseUtil::get_query_param(url);
        string token = params["token"];
        string filehash = params["filehash"];

        ParseUtil::verify_token(req, resp, [req,resp,token,filehash](User user){
            if(user.id != 0 && CryptoUtil::verify_token(token,user)){
                string sql_query = "select * from tbl_file where hashcode = '" + filehash + "';";
                cout << "[SQL]" << sql_query << endl;
                resp->MySQL(mysql_url,sql_query,[resp](MySQLResultCursor *cursor){
                    if(cursor->get_cursor_status()==MYSQL_STATUS_GET_RESULT && cursor->get_rows_count()==1){
                        map<string,MySQLCell> record;
                        string filename;
                        string filepath;
                        if(cursor->fetch_row(record)){
                            filename = record["filename"].as_string();
                            filepath = "resources/" + filename;
                            cout << "filepath: " << filepath << endl;
                        }else{
                            resp->set_status(HttpStatusNotFound);
                            return;
                        }
                        
                        resp->set_header_pair("Content-Disposition", "attachment; filename=\""+ filename +"\"");
                        resp->File(filepath);
                    }else if(cursor->get_rows_count()!=1){
                        resp->set_status(HttpStatusNotFound);
                    }else{
                        resp->set_status(HttpStatusInternalServerError);
                    }
                });
            }else{
                resp->set_status(HttpStatusUnauthorized);
            }
        });
    });
}